<template>
  <div class="novel-container">
    <div class="novel-main-title-box">
      <div v-show="hideShowBtn" class="novel-main-title">{{ theNovelCnName }}</div>
      <div class="options-box">
        <div v-show="hideShowBtn" class="speech-rate-select-box">
          <span>播放语速：</span>
          <el-select v-model="speechRate">
            <el-option :value="1">1</el-option>
            <el-option :value="1.5">1.5</el-option>
            <el-option :value="2">2</el-option>
            <el-option :value="3">3</el-option>
            <el-option :value="4">4</el-option>
            <el-option :value="5">5</el-option>
            <el-option :value="8">8</el-option>
            <el-option :value="10">10</el-option>
          </el-select>
        </div>
        <el-button v-show="hideShowBtn" type="primary" @click="startSpeechNovel">从开头开始播放</el-button>
        <el-button v-show="hideShowBtn" type="primary" @click="fromSelectStartSpeechNovel">
          从选中文本开始播放
        </el-button>
        <el-button v-show="hideShowBtn" type="danger" @click="stopSpeechNovel">停止播放</el-button>
        <el-button v-show="hideShowBtn" type="warning" v-if="isPause" @click="pauseSpeechNovel">暂停播放</el-button>
        <el-button v-show="hideShowBtn" type="success" v-else @click="resumeSpeechNovel">继续播放</el-button>
        <el-button v-if="hideShowBtn" type="info" @click="hideShowBtn = false">▲</el-button>
        <el-button v-else type="info" @click="hideShowBtn = true">▼</el-button>
      </div>
    </div>
    <div class="novel-content-box">
      <div v-if="isLoad" class="novel-content">
        <Loading></Loading>
      </div>
      <div v-else class="novel-content" v-html="showTxtCentent"></div>
    </div>
    <div v-show="hideShowBtn" class="novel-footer-box">
      <h5>当前章节：第{{ currentChapterNum }}章&nbsp;&nbsp;&nbsp;最大章节数：{{ totalChapterNum }}章</h5>
      <div class="btn-box">
        <el-button type="primary" :disabled="currentChapterNum <= 1" @click="changeLastChapter">上一章</el-button>
        <el-button type="primary" @click="changeNextChapter">下一章</el-button>
        <div class="jump-box">
          <div class="text">跳转到</div>
          <el-input v-model="wantJumpPage" />
          <div class="text">章</div>
          <el-button type="primary" @click="jumpPage">跳转</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ElMessage } from "element-plus"
import { queryNovelChapter } from "@/apis/novel"
// 接口是一种约束（规范），不是值，在导入时要在前面加上type
import { type NovelParamsInter, type ReadRecordInter } from "@/types/novel"

const route = useRoute()

const theNovelName = ref("")
const theNovelCnName = ref("")
const allTxtContent = ref("")
const currentChapterNum = ref(0)
const totalChapterNum = ref(0)
const wantJumpPage = ref(0)
const isPause = ref(true)
const isLoad = ref(true)
const speechRate = ref(1.5)
const hideShowBtn = ref(true)
const synth = window.speechSynthesis
const speech = new SpeechSynthesisUtterance()
const speechFinishNum = ref(0)
const isPlay = ref(false)

// 显示当前章节内容
const showTxtCentent = computed(() => `${allTxtContent.value}`.replace(/\n/g, "<br/>").replace(/\r/g, "&nbsp;"))

watch(
  () => currentChapterNum.value,
  (newV) => {
    console.log("currentChapterNum newV", newV)
    console.log("speechFinishNum", speechFinishNum.value)
    if (isPlay.value && currentChapterNum.value > speechFinishNum.value) {
      startSpeechNovel()
    }
  },
)

const getNovelChapter = async (novelParams: NovelParamsInter) => {
  try {
    isLoad.value = true
    const { novelName, chapterNum } = novelParams
    const params = { novelName, chapterNum }
    const res = await queryNovelChapter(params)
    // console.log("查询小说章节内容：", res)
    const { novelContent, currentChapter, totalChapter } = res.data
    allTxtContent.value = novelContent
    currentChapterNum.value = currentChapter
    totalChapterNum.value = totalChapter
    wantJumpPage.value = currentChapter
    rememberCurrentRead()
    isLoad.value = false
  } catch (error) {
    console.error("查询小说章节内容出错：", error)
    ElMessage.error("查询小说章节内容出错")
    isLoad.value = false
  }
}

const initData = () => {
  const { novelName, novelCnName } = route.params
  wantJumpPage.value = 1
  theNovelName.value = `${novelName}`
  theNovelCnName.value = `${novelCnName}`
  loadRememberRead()
}

const changeLastChapter = () => {
  if (currentChapterNum.value <= 1) {
    console.warn("已经是第一章")
    return
  }
  const params: NovelParamsInter = { novelName: `${theNovelName.value}`, chapterNum: currentChapterNum.value - 1 }
  getNovelChapter(params)
}
const changeNextChapter = () => {
  if (currentChapterNum.value >= totalChapterNum.value) {
    console.warn("已经是最后一章")
    return
  }
  const params: NovelParamsInter = { novelName: `${theNovelName.value}`, chapterNum: currentChapterNum.value + 1 }
  getNovelChapter(params)
}
const jumpPage = () => {
  const pageNum = Number(wantJumpPage.value)
  if (typeof pageNum !== "number" || Number.isNaN(pageNum)) {
    ElMessage.error("非法数字")
    return
  }
  wantJumpPage.value = Math.floor(wantJumpPage.value)
  if (wantJumpPage.value < 1) {
    wantJumpPage.value = currentChapterNum.value
    ElMessage.warning("最少为一章")
    return
  }
  if (wantJumpPage.value > totalChapterNum.value) {
    wantJumpPage.value = currentChapterNum.value
    ElMessage.warning("超出总章节数")
    return
  }
  const params: NovelParamsInter = { novelName: `${theNovelName.value}`, chapterNum: wantJumpPage.value }
  getNovelChapter(params)
}

synth.onvoiceschanged = (event) => {
  console.log("event", event.target)
}
// 播放完的回调
speech.onend = (event) => {
  // console.log("播完event", event)
  speechFinishNum.value = currentChapterNum.value
  changeNextChapter()
}
// 文字转语音
const textToSpeech = (text: string) => {
  const speechText = text.replace(/&nbsp/g, "").replace(/<br\/>/g, "")
  speech.text = speechText // 播放文本
  speech.rate = speechRate.value || 1.5 // 播放语速。默认值1，区间[0.1,10]
  speech.pitch = 1.2 // 音调高低。默认值1，区间[0,2]
  speech.volume = 1 // 播放音量。默认值1，区间[0,1]
  speech.lang = "zh-CN" // 设置播放语言。zh-CN：中文
  return speech
}
const startSpeechNovel = () => {
  if (synth.speaking || synth.paused) {
    stopSpeechNovel()
  }
  const textSpeech = textToSpeech(showTxtCentent.value)
  synth.speak(textSpeech)
  isPlay.value = true
}
const getSelectText = () => {
  let selectText = ""
  const selection = window.getSelection()
  if (selection) {
    // 获取选中的文本，确保没有任何空格或换行符
    const fromSelectText = Array.from(selection.toString()).join("").trim()
    console.log("fromSelectText", fromSelectText)
    if (fromSelectText !== "") {
      const selectTextIndex = showTxtCentent.value.indexOf(fromSelectText)
      console.log("selectTextIndex", selectTextIndex)
      if (selectTextIndex !== -1) {
        selectText = showTxtCentent.value.substring(selectTextIndex)
      }
    }
  }
  return selectText
}
// 从选中文本开始播放
const fromSelectStartSpeechNovel = () => {
  const selectText = getSelectText()
  console.log("selectText", selectText)
  if (selectText === "") {
    ElMessage.warning("未选中小说内容")
    return
  }
  if (synth.speaking || synth.paused) {
    stopSpeechNovel()
  }
  const textSpeech = textToSpeech(selectText)
  synth.speak(textSpeech)
  isPlay.value = true
}
const stopSpeechNovel = () => {
  synth.cancel()
  isPause.value = true
  isPlay.value = false
}
const pauseSpeechNovel = () => {
  synth.pause()
  isPause.value = false
  isPlay.value = false
}
const resumeSpeechNovel = () => {
  synth.resume()
  isPause.value = true
  isPlay.value = true
}

// 记录当前小说的当前阅读的页
const rememberCurrentRead = () => {
  const readRecords = JSON.parse(localStorage.getItem("readRecords") || "[]")
  const hasRecord = readRecords.some((item: ReadRecordInter) => item.name === theNovelName.value)
  if (hasRecord) {
    for (let index = 0; index < readRecords.length; index++) {
      const item = readRecords[index]
      if (item.name === theNovelName.value) {
        item.lastReadChapter = currentChapterNum.value
        break
      }
    }
  } else {
    const newReadRecord = {
      name: theNovelName.value,
      lastReadChapter: currentChapterNum.value,
    }
    readRecords.push(newReadRecord)
  }
  localStorage.setItem("readRecords", JSON.stringify(readRecords))
}
// 加载上次阅读位置
const loadRememberRead = () => {
  try {
    // 不存在阅读记录则从第一章开始加载
    let lastReadChapter = 1
    const readRecords = JSON.parse(localStorage.getItem("readRecords") || "[]")
    const recordItem = readRecords.filter((item: ReadRecordInter) => item.name === theNovelName.value)[0]
    if (recordItem) {
      lastReadChapter = recordItem.lastReadChapter
    }
    console.log("lastReadChapter", lastReadChapter)
    currentChapterNum.value = lastReadChapter
    wantJumpPage.value = lastReadChapter
    totalChapterNum.value = lastReadChapter
    jumpPage()
    if (lastReadChapter > 1) {
      ElMessage.success("已加载至上次阅读位置")
    }
  } catch (error) {
    console.error("error", error)
    ElMessage.error("加载上次阅读位置失败")
  }
}

initData()

onBeforeUnmount(() => {
  synth.cancel()
})
</script>

<style lang="scss" scoped>
.novel-container {
  background-color: #000000;
  color: #414141;
  width: 100%;
  height: 100vh;
  padding: 10px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;

  .novel-main-title-box {
    text-align: center;
    .novel-main-title {
      font-weight: 700;
      font-size: 20px;
    }
    .options-box {
      padding: 4px 0;
      box-sizing: border-box;
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      align-items: center;
      .speech-rate-select-box {
        margin-right: 12px;
        .el-select {
          width: 80px;
        }
      }
    }
  }
  .novel-content-box {
    height: 82vh;
    padding: 10px;
    box-sizing: border-box;
    overflow: auto;
    .novel-content {
      width: 100%;
      height: 100%;
    }
  }
  .novel-footer-box {
    .btn-box {
      display: flex;
      flex-wrap: wrap;
      align-items: center;

      .jump-box {
        margin: 0 10px;
        display: flex;
        justify-content: center;
        align-items: center;

        .text {
          padding: 0 4px;
          box-sizing: border-box;
        }

        .el-input {
          width: 100px;
        }
      }
    }
  }
}
</style>
